package com.glepoch.springbootsecuritymybatis.compoment.requestwrapper;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 请求体参数包装类，用于解决二次读取body数据问题
 */
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {

    private static String contentType = null;
    private HttpServletRequest request = null;
    /**
     * 用于存储body内容的变量
     */
    private byte[] requestBody = null;

    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        this.request = request;
        this.contentType = request.getContentType();
        //将原requestbody数据copy到requestBody中
        this.requestBody = StreamUtils.copyToByteArray(request.getInputStream());
        String bodyStr = null;
        if (this.requestBody != null)
            bodyStr = new String(this.requestBody);
        Map map = null;
        if (!StringUtils.isEmpty(bodyStr)) {
            map = new ObjectMapper().readValue(bodyStr, Map.class);
            map = readDataAndTrim(map);
            this.requestBody = new ObjectMapper().writeValueAsBytes(map);
        }
    }

    private Map readDataAndTrim(Map map) {
        if (map == null)
            return null;
        Set<String> keySet = map.keySet();
        for (String key : keySet) {
            Object objValue = map.get(key);
            if (objValue != null && objValue instanceof String) {
                String s = objValue.toString();
                String trim = s.trim();
                map.put(key, trim);
            } else if (objValue != null && objValue instanceof Map) {
                Map map1 = readDataAndTrim((Map) objValue);
                map.put(key, map1);
            }
        }
        return map;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        //模拟构建一个流对象，用于每次的数据读取，每次都会创建一个新的
        final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);

        return new ServletInputStream() {

            @Override
            public int read() throws IOException {
                return bais.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }
        };
    }

    //用新创建的字节流对象来构建字符流对象
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public String getParameter(String name) {
        if (!StringUtils.isEmpty(contentType) && contentType.toLowerCase().contains("application/json")) {
            String s = null;
            try {
                s = readBodyData(name);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return s;
        }
        String parameter = super.getParameter(name);
        if (parameter != null)
            parameter = parameter.trim();
        return parameter;
    }

    private String readBodyData(String name) throws IOException {
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = null;
        try {
            bufferedReader = this.getReader();
            if (bufferedReader != null) {
                char[] charBuffer = new char[128];
                int bytesRead = -1;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            } else {
                stringBuilder.append("");
            }
        } catch (IOException ex) {
            throw ex;
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException ex) {
                    throw ex;
                }
            }
        }
        String bodyData = stringBuilder.toString();
        if (!StringUtils.isEmpty(bodyData)) {

            String o = getParameterInObj(bodyData, name);

            return o;

        }
        return null;
    }

    private String getParameterInObj(String bodyDataStr, String name) {
        if (StringUtils.isEmpty(name) || StringUtils.isEmpty(bodyDataStr))
            return null;
        JSONObject bodyDataJsonObj = JSONObject.parseObject(bodyDataStr);
        String[] names = name.split("\\.");
        for (int i = 0; i < names.length; i++) {
            Object o = bodyDataJsonObj.get(names[i]);
            if (o != null && !(o instanceof List)) {
                String s = o.toString();
                if (s.contains("{")) {
                    bodyDataJsonObj = JSONObject.parseObject(s);
                } else {
                    return s;
                }
            } else {
                break;
            }

        }
        return null;
    }

    @Override
    public Enumeration<String> getParameterNames() {
        return super.getParameterNames();
    }


}
